/*
 * 
 * Date                   By              Description
 * -------------------    -----------     -------------------------------------------
 * 2018年3月7日    xurl         Create the class
 */

package com.xu.demo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

/**
 * @FileName CountMojo.java
 * @Description: 统计代码行数
 * 
 * @Date 2018年3月7日
 * @author xurl
 * @version 1.0.1
 * 
 * name: 唯一必须声明的标注，当用户使用命令行调用插件
 * defaultPhase: 默认将该目标绑定值Default生命周期的某个阶段
 * requiresProject: 表示该目标是否必须在一个Maven项目中运行
 * threadSafe: 线程安全
 * requiresDependencyResolution: 表示在运行改Mojo之前必须解析所有的指定范围的依赖 依赖范围有complile, test 默认值为runtime
 * requiresOnline: 表示是否要求Maven必须在线状态, 默认值是false
 * requiresReports: 表示是否要求项目报告已经生产, 默认值是false
 * 
 */
@Mojo(name = "count", defaultPhase = LifecyclePhase.TEST, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.RUNTIME)
public class CountMojo extends AbstractMojo {

	private static final String[] INCLUDES_DEFAULT = { "java", "xml", "properties" };

	/**
	 * 根目录  默认 /
	 * required 为true,必填
	 * readonly 为true,只读不能修改
	 */
	@Parameter(defaultValue = "${project.basedir}", required = true, readonly = true)
	private File basedir;

	/**
	 * main目录  默认 /src/main/java
	 */
	@Parameter(defaultValue = "${project.build.sourceDirectory}", required = true, readonly = true)
	private File sourceDirectory;

	/**
	 * test目录 默认/src/test/java
	 */
	@Parameter(defaultValue = "${project.build.testSourceDirectory}", required = true, readonly = true)
	private File testSourceDirectory;

	/**
	 * resources目录 默认/src/main/resources
	 */
	@Parameter(defaultValue = "${project.build.resources}", required = true, readonly = true)
	private List<Resource> resources;

	/**
	 * testResources目录 默认/src/test/testResources
	 */
	@Parameter(defaultValue = "${project.build.testResources}", required = true, readonly = true)
	private List<Resource> testResources;

	/**
	 * 包含哪些后缀文件,进行统计
	 */
	@Parameter
	private String[] includes;

	private long total = 0l;

	@Override
	public void execute() throws MojoExecutionException, MojoFailureException {
		if (includes == null || includes.length == 0) {
			includes = INCLUDES_DEFAULT;
		}
		try {
			//source目录下
			countDir(sourceDirectory);

			//testSource目录下
			countDir(testSourceDirectory);

			//resources目录下
			for (Resource resource : resources) {
				countDir(new File(resource.getDirectory()));
			}

			//testResources目录下
			for (Resource resource : testResources) {
				countDir(new File(resource.getDirectory()));
			}

			getLog().info("total lines:" + total);

		} catch (IOException e) {
			throw new MojoExecutionException("Unable to count lines of code.", e);
		}
	}

	/**
	 * @Title: countDir
	 * @Description: 统计目录
	 * @param dir
	 * @throws IOException
	 * @author xurl
	 * @date 2018年3月7日
	 */
	private void countDir(File dir) throws IOException {
		if (!dir.exists()) {
			return;
		}

		List<File> collected = new ArrayList<File>();

		collectFiles(collected, dir);

		int lines = 0;

		for (File sourceFile : collected) {
			lines += countLine(sourceFile);
		}

		String path = dir.getAbsolutePath().substring(basedir.getAbsolutePath().length());

		getLog().info(path + ":" + lines + " lines of code in " + collected.size() + " files");

		total += lines;
	}

	/**
	 * @Title: collectFiles
	 * @Description: 统计文件
	 * @param collected
	 * @param file
	 * @author xurl
	 * @date 2018年3月7日
	 */
	private void collectFiles(List<File> collected, File file) {
		if (file.isFile()) {
			for (String include : includes) {
				if (file.getName().endsWith("." + include)) {
					collected.add(file);
					break;
				}
			}
		} else {
			for (File sub : file.listFiles()) {
				collectFiles(collected, sub);
			}
		}
	}

	/**
	 * @Title: countLine
	 * @Description: 统计行数
	 * @param file
	 * @return
	 * @throws IOException
	 * @author xurl
	 * @date 2018年3月7日
	 */
	private int countLine(File file) throws IOException {
		BufferedReader reader = new BufferedReader(new FileReader(file));

		int line = 0;

		try {
			while (reader.ready()) {
				reader.readLine();
				line++;
			}
		} finally {
			reader.close();
		}
		return line;
	}

}
